/*********************************************************************************
 *      Copyright:  (C) 2019 Wu Yujun<540726307@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  sms_cat.c
 *    Description:  This file Demo sms cat
 *                 
 *        Version:  1.0.0(2019年07月30日)
 *         Author:  Wu Yujun <540726307@qq.com>
 *      ChangeLog:  1, Release initial version on "2019年07月30日 11时43分41秒"
 *                 
 ********************************************************************************/

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "server_socket.h"
#include "at_cmd.h"
#include "log.h"
#include "gsmd.h"
#include "get_time.h"

#define DEAFUALT_LOG    "daemon_log"
#define CLOSE_CLIENT    -4


#ifndef BUF_SIZE
#define BUF_SIZE        512
#endif



int analysis_handler(const char *buf,int cli_fd, st_gsmd_ctx *gsmd_ctx ); 
int analysis_sms(const char *buf, char *gmgs, int gmgs_size, char *content, int content_size) ; 
int analysis_pdusms(const char *buf, int *lenth, char *content, int content_size) ; 
int analysis_textsms(const char *buf, char *phone, int phone_size,char *content, int content_size) ; 

int g_stop = 0 ;
void sig_handler(int sig_num)
{
    if(sig_num == SIGUSR1)
    {
        g_stop = 1 ;
    }
}


void print_usage(const char *program_name) 
{  
    printf("\n%s -- (2019.7.31)\n", program_name);  
    printf(" Usage: %s -p <server_port>  [-h <server_use_help>]\n", program_name);  
    printf("        -p --port       the server listen port\n") ;
    printf("        -h --help       the server file how to use\n");  
    printf("        -d --daemon     the server progame running in backgruand\n");  

    return ;
}  

int main(int argc, char **argv)
{
    int                 rv = -1 ;
    char                *program_name ;
    char                *ip = NULL ;
    int                 port = -1 ;
    int                 opt = -1 ;
    int                 daemon_run = 0 ;
    int                 log_fd = -1 ;
    int                 serv_fd = -1 ;
    int                 cli_fd ;
    int                 conn_flag = 0 ;
    char                buf[BUF_SIZE] ;
    st_gsmd_ctx         *gsmd_ctx = NULL;
    char                time[128] ;


    program_name = basename(argv[0]) ;
    const char *short_opts = "i:p:hd";                    
    const struct option long_opts[] =   {  
        {"help", no_argument, NULL, 'h'},    
        {"ip", required_argument, NULL, 'i'},
        {"daemon", no_argument, NULL, 'd'},  
        { "port", required_argument, NULL, 'p'},  
        {0, 0, 0, 0} 
    }; 
    while ((opt= getopt_long(argc, argv, short_opts, long_opts,NULL)) != -1) 
    {
        switch (opt) 
        {
            case 'i':
                ip = optarg ;
                break ;
            case 'p':
                port = atoi(optarg) ;
                break ;
            case 'd':
                daemon_run = 1 ;
                break ;
            case 'h':
                print_usage(program_name) ;
                return 0 ;
        }
    }

    if( port < 0 )
    {
        print_usage(program_name) ;
        return -1 ;
    }
    if(daemon_run == 1)                      
    {
        printf("program %s running in backgrund\n", program_name);
        if( (log_fd = open(DEAFUALT_LOG, O_CREAT|O_RDWR, 0666)) < 0)
        {
            printf("[FATAL]:open() failed:%s\n", strerror(errno)) ;
            return -2 ;
        }
        dup2(log_fd, STDOUT_FILENO) ;
        dup2(log_fd, STDERR_FILENO) ;
        daemon(1,1) ;
    }

    signal(SIGUSR1, sig_handler) ;
    /* init socket, socket(),bind(),listen() */
    serv_fd = creat_socket(ip, port);
    if(serv_fd < 0)
    {
        printf("[FATAL]:creat_socket() failed\n") ;
        goto cleanup ;
    }
    /*   init struct gsmd_ctx   */
    gsmd_ctx = init_gprs_module(port) ;
    if(!gsmd_ctx)
    {
        printf("[FATAL]:init_gprs_module() error\n") ;
        return -1 ;
    }
    while(!g_stop)
    {
        if(daemon_run) //if running in backgrund, log size should be limited
        {
            log_roll_back(log_fd) ;
        } 

        memset(time, 0, sizeof(time)) ;
        get_time(time) ;
        printf("\n%s\n",time) ;

        if( conn_flag == 0 )
        {
            cli_fd = accept_client(serv_fd) ;
            if(cli_fd < 0)
            {
                printf("[ERROR]:accept client failed\n") ;
                continue ;
            }
            gsmd_ctx->gsmSocket.cli_fd = cli_fd ;
            conn_flag = 1 ;
        }
        memset(buf, 0, sizeof(buf)) ;
        rv = read(cli_fd, buf, sizeof(buf)) ; 
        if(rv <= 0)
        {
            printf("[ERROR]:read from client[%d] error,close client\n",cli_fd) ;
            close(cli_fd) ;
            cli_fd = -1 ;
            conn_flag = 0 ;
            continue ;
        }
        printf("[NOMAL]:read from client:%s\n", buf) ;

        rv = analysis_handler(buf,cli_fd, gsmd_ctx )  ;
        if(rv<0)
        {
            if(rv == CLOSE_CLIENT)
            {
                close(cli_fd) ;
                cli_fd = -1 ;
                conn_flag = 0 ;
                continue ;
            }
            rv = write(cli_fd, "Error,Please try again", strlen("Error,Please try again")) ;
            if( rv < 0 )
            {
                printf("ERROR:write to client[%d] error,close client\n",cli_fd) ;
                close(cli_fd) ;
                cli_fd = -1 ;
                conn_flag = 0 ;
                continue ;
            }
            continue ;
        }

    }//while(!g_stop)

    printf("Program will exit....\n") ;

cleanup:
    destroy_gsmd(gsmd_ctx) ;
    if(serv_fd)
    {
        close(serv_fd) ;
    }
    if(cli_fd)
    {
        close(cli_fd) ;
    }
    if(daemon_run)
    {
        close(log_fd) ;
    }

    return 0 ;
}/* End Of Main */


/***************************************************************************************************
 * Describe: analysis and handler string of read form client,
 *      it's format:
 *      "rec_sms" to recevie sms , 
 *      "send_text/${telphone number}/${sms content}" to send text sms
 *      "send_pdu/${send content len}/${pdu_sms content}" to send pdu sms
 * Return:
 *          sucess return 0, fail return negative,fail and should close client return  CLOSE_CLIENT
 *****************************************************************************************************/
int analysis_handler(const char *buf,int cli_fd, st_gsmd_ctx *gsmd_ctx ) 
{
    char        sbuf[256] ;
    int         rv = -1 ;
    int         i = 0 ;
    char        phone[64] ;
    char        content[512] ;
    int         length = 0 ;
    char        rec_buf[512] ;
    int         index[256] ;
    char        where[32] ;



    if(strstr(buf,"send_text") != NULL)
    {
        memset(phone, 0, sizeof(phone)) ;
        /*  send_text/${telphone number}/${sms content}    */
        rv = analysis_textsms(buf, phone, sizeof(phone), content, sizeof(content)) ;
        if(rv < 0)
        {
            printf("[ERROR]: analysis text sms failed\n") ;
            return -1 ;
        }
        rv = check_regsiter(Data_COM,gsmd_ctx) ;
        if(rv != OK)
        {
            printf("[ERROR]:sim card isn't regsiter\n") ;
            return -2 ;
        }
        rv = send_mess(Data_COM,phone,content);
        if(rv < 0)
        {
            printf("[ERROR]:send sms fail\n") ;
            return -3 ;
        }
        printf("[NOMAL]:send text sms sucessful\n") ;
        rv = write(cli_fd, "send text sms OK!", strlen("send text sms OK!")) ;
        if( rv < 0 )
        {
            printf("ERROR:write to client[%d] error,close client\n",cli_fd) ;
            return CLOSE_CLIENT ;
        }

    }

    else if(strstr(buf, "send_pdu") != NULL)
    {
        /*  send_pdu/${send content len}/${sms content}    */
        rv = analysis_pdusms(buf, &length, content, sizeof(content)) ;
        if(rv < 0)
        {
            printf("[ERROR]:analysis pdu sms failed\n") ;
            return -1 ;
        }
        rv = check_regsiter(Data_COM,gsmd_ctx) ;
        if(rv != OK)
        {
            printf("[ERROR]:sim card isn't regsiter\n") ;
            return -2 ;
        }
        rv = send_pdu_sms(Data_COM, length, content) ;
        if(rv < 0)
        {
            printf("[ERROR]:send pdu sms fail\n") ;
            return -3 ;
        }
        printf("[NOMAL]:send pdu sms sucessful\n") ;
        rv = write(cli_fd, "send pdu sms OK!", strlen("send pdu sms OK!")) ;
        if( rv < 0 )
        {
            printf("ERROR:write to client[%d] error,close client\n",cli_fd) ;
            return CLOSE_CLIENT ;
        }
    }

    else if(!strcmp(buf,"rec_sms"))
    {
        gsmd_ctx->comport = comport_init(Data_COM, 115200,8,'N',1,'N') ;
        if(!gsmd_ctx->comport)
        {
            printf("[ERROR]:comport_init() failed\n") ;
            return -1 ;
        }
        gsmd_ctx->comport->fd = open_comport(gsmd_ctx->comport) ;
        if(gsmd_ctx->comport->fd < 0)
        {
            printf("[ERROR]:Open_comport() Failed\n") ;
            return -2 ;
        }
        rv = check_cmgl(gsmd_ctx->comport, index, sizeof(index), ALL) ;
        if(rv < 0)
        {
            printf("[ERROR]:List sms failed\n") ;
            comport_term(gsmd_ctx->comport) ;
            return -3 ;
        }
        memset(sbuf, 0, sizeof(sbuf)) ;
        snprintf(sbuf, sizeof(sbuf),"please input index number you want to read,have %d sms can read,",rv) ;
        for(i=0; i<rv; i++)
        {
            memset(where, 0, sizeof(where)) ;
            snprintf(where, sizeof(where),"index[%d]", index[i]);
            strcat(sbuf, where ) ;
        }
        rv = write(cli_fd, sbuf, strlen(sbuf)) ;
        if( rv < 0 )
        {
            printf("ERROR:write to client[%d] error,close client\n",cli_fd) ;
            return CLOSE_CLIENT ;
        }
        memset(rec_buf, 0, sizeof(rec_buf)) ;
        rv = read(cli_fd, rec_buf, sizeof(rec_buf)) ; 
        if(rv <= 0)
        {
            printf("[ERROR]:read from client[%d] error,close client\n",cli_fd) ;
            return CLOSE_CLIENT ;
        }

        rv = atoi(rec_buf) ;
        memset(rec_buf, 0, sizeof(rec_buf)) ;
        if( read_sms(gsmd_ctx->comport, rv, rec_buf, sizeof(rec_buf)) == 0)
        {
            printf("Receive sms:%s",rec_buf) ;
        }
        else
        {
            printf("ERROR read_sms index%d\n",index[i]) ;
            return -5 ;
        }
        comport_term(gsmd_ctx->comport) ;
        rv = write(cli_fd, rec_buf, strlen(rec_buf)) ;
        if( rv < 0 )
        {
            printf("ERROR:write to client[%d] error,close client\n",cli_fd) ;
            return CLOSE_CLIENT ;
        }
    }
    else{
        printf("[ERROR]:Unkonw!\n") ;
        return -1 ;
    }
    return 0 ;
}

/***********************************************************************
 *  Describe: analysis text sms request,
 *      it's format:
 *      "send_text/${telphone number}/${sms content}" to send text sms
 * Return:
 *          sucess return 0, fail return negative.
 * *********************************************************************/
int analysis_textsms(const char *buf, char *phone, int phone_size,char *content, int content_size) 
{
    int     rv = -1 ;
        
    if(buf == NULL || phone == NULL || phone_size <= 0 || content == NULL || content_size <= 0)
    {
        printf("Invail parameter in %s\n", __FUNCTION__) ;
        return -1 ;
    }

    rv = analysis_sms(buf, phone, phone_size, content, content_size) ; 
    if(rv < 0)
    {
        printf("analysis sms failed\n") ;
        return -2 ;
    }
    return 0 ;
}


/***************************************************************************************************
 * Describe: analysis send pdu sms request 
 *      it's format:
 *      "send_pdu/${send content len}/${pdu_sms content}" to send pdu sms
 * Return:
 *          sucess return 0, fail return negative.
 *****************************************************************************************************/
int analysis_pdusms(const char *buf, int *lenth, char *content, int content_size) 
{
    char    len[16] ;
    int     rv = -1 ;
        
    if(buf == NULL || lenth == NULL || content == NULL || content_size <= 0)
    {
        printf("Invail parameter in %s\n", __FUNCTION__) ;
        return -1 ;
    }

    memset(len, 0, sizeof(len)) ;
    rv = analysis_sms(buf, len, sizeof(len), content, content_size) ; 
    if(rv < 0)
    {
        printf("analysis sms failed\n") ;
        return -2 ;
    }
    *lenth = atoi(len) ;
    return 0 ;
}


/***************************************************************************************
 *  Describe: analysis for analysis_pdusms() and analysis_textsms()
 *      format: ${request}/${gmgs content}/${sms contine}
 *      pdu mode gmgs content is sms content length, text mode gmgs content is telephone
 *  Return:
 *          sucess return 0, fail return negative.
 * ****************************************************************************************/
int analysis_sms(const char *buf, char *gmgs, int gmgs_size, char *content, int content_size) 
{
    const char    *ptr_start = NULL ;
    char    *ptr_end = NULL ;
    
    ptr_start = buf ;
    ptr_start = strstr(ptr_start, "/") ;
    if(ptr_start == NULL)
    {
        return -2 ;
    }
    ptr_start = ptr_start+1 ;
    if(ptr_start == NULL)
    {
        return -3 ;
    }
    ptr_end = strstr(ptr_start, "/") ;
    if(gmgs_size < (ptr_end - ptr_start))
    {
        printf("GMGS size is too small\n") ;
        return -4 ;
    }
    strncpy(gmgs, ptr_start, (ptr_end - ptr_start)) ;
    ptr_start = ptr_end + 1 ;
    if(ptr_start == NULL)
    {
        return -5 ;
    }
    strcpy(content, ptr_start ) ;
   
#if 0
    printf("GMGS=%s, content=%s\n", gmgs, content) ;
#endif

    return 0 ;
}
